package com.intretech.umsin.common.service;


import com.baomidou.mybatisplus.core.metadata.IPage;
import com.intretech.umsin.common.annotation.Dict;
import com.intretech.umsin.common.constant.CommonConstant;
import com.intretech.umsin.common.entity.Assignment;
import com.intretech.umsin.common.entity.DictConfigModel;
import com.intretech.umsin.common.entity.DictModel;
import com.intretech.umsin.common.utils.JsonUtils;
import com.intretech.umsin.common.web.ApiResult;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @version V1.0
 * @ClassName: AbstractParseDictServive
 * @Description: 功能描述 处理字典转换/码名映射
 * @author: 李启联
 * @date: 2022-6-8 18:44
 * @Copyright: Copyright (c) 2022
 */
public abstract class  AbstractParseDictServive implements ParseDictService {

    @Override
    public Object parseDictText(Object result) {
        if (result instanceof ApiResult){
            return translateAllDict((ApiResult)result);
        }
        return result;
    }


    /**
     * 翻译字典
     * @param result
     * @return
     */
    private ApiResult translateAllDict(ApiResult result) {
        Object resultData = result.getData();
        if(ObjectUtils.isEmpty(resultData)){return result;}
        //1.获取所有标注@Dict的配置
        List<DictConfigModel> dictConfigs = getDictConfigs(resultData);
        //如果没有@Dict则直接返回
        if(CollectionUtils.isEmpty(dictConfigs)){return result;}

        //把所有涉及到字典配置的单字典一次性查询出来
        List<DictModel> dictList = getAllSingleDictByConfigs(dictConfigs);

        if (resultData instanceof Collection) {
            List<Map<String,Object>> ls = new ArrayList<>();
            ((Collection) resultData).forEach(e-> {
                Map data = JsonUtils.toMap(JsonUtils.toJsonString(e));
                Map map = translateObjectDict(data, dictConfigs, dictList);
                ls.add(map);
            });
            result.setData(ls);
        }
        else if (resultData instanceof IPage) {
            List<Map<String,Object>> ls = new ArrayList<>();
            ((IPage)resultData).getRecords().forEach(e->{
                Map<String,Object> data = JsonUtils.toMap(JsonUtils.toJsonString(e));
                Map<String,Object> map = translateObjectDict(data, dictConfigs, dictList);
                ls.add(map);
            });
            ((IPage)resultData).setRecords(ls);

        } else if (resultData instanceof Assignment) {
            Map data = JsonUtils.toMap(JsonUtils.toJsonString(resultData));
            Map map = translateObjectDict(data, dictConfigs, dictList);
            result.setData(map);
        }

        return result;
    }


    /***
     * 翻译实例对象字典
     * @param obj 需要字典翻译的实例对象
     * @param dictConfigs 字典翻译配置集合
     * @param dictList  一次性返回的字典数据
     * @return
     */
    Map<String,Object> translateObjectDict(Map<String,Object> obj,List<DictConfigModel> dictConfigs,List<DictModel> dictList){
        List<String> dictText = new LinkedList<>();
        for (DictConfigModel dictConfig : dictConfigs) {
            dictText.clear();
            //得到实体属性值
            String filedValue = String.valueOf(obj.get(dictConfig.getFiledName()));
            if(StringUtils.isEmpty(filedValue)){continue;}

            List<String> values = Arrays.asList(filedValue.split(","));
            if(StringUtils.isEmpty(dictConfig.getDictTable())){//单字典处理
                for (String v:values) {
                    Optional<DictModel> dictModelOptional = dictList.stream().filter(e -> e.getDictCode().equals(dictConfig.getDicCode())).filter(e-> e.getValue().equals(v)).findFirst();
                    if (dictModelOptional.isPresent()){
                        DictModel dictModel = dictModelOptional.get();
                        dictText.add(dictModel.getText());
                    }else {
                        dictText.add("");
                    }
                }
                obj.put(dictConfig.getFiledName()+ CommonConstant.DICT_TEXT_SUFFIX,String.join(",", dictText));

            }else {//表字典处理
                String dictTable = dictConfig.getDictTable();
                String text = dictConfig.getDicText();
                String code = dictConfig.getDicCode();
                List<DictModel> dictModels = queryTableDictByKeys(dictTable, text, code, values);
                for (String value:values) {
                    Optional<DictModel> dictModelOptional = dictModels.stream().filter(e -> e.getValue().equalsIgnoreCase(value)).findFirst();
                    if(dictModelOptional.isPresent()){
                        DictModel dictModel = dictModelOptional.get();
                        dictText.add(dictModel.getText());
                    }else {
                        dictText.add("");
                    }
                }
                obj.put(dictConfig.getFiledName()+ CommonConstant.DICT_TEXT_SUFFIX,String.join(",", dictText));
            }
        }

        return obj;
    }


    /**
     * 获得目标实例对象 (即: ApiResult对象里属性data属性里包装对应的实例对象)
     * 例 : List<User> 则是返回 User对象实例
     * @param resultData  ApiResult里对应的data对象
     * @return
     */
    private Object getInstanceObject(Object resultData){

        Object obj = null;
        if (resultData instanceof Collection) {
            if (((Collection) resultData).stream().allMatch(r -> r instanceof Assignment)) {
                obj = ((Collection) resultData).stream().findAny().get();
            }
        }
        else if (resultData instanceof IPage) {
            if (((IPage) resultData).getRecords().get(0) instanceof Assignment) {
                obj = ((IPage) resultData).getRecords().get(0);
            }
        } else if (resultData instanceof Assignment) {
            obj = resultData;
        }

        return obj;
    }

    /**
     * 得到目标实体对象的所有字典配置集合
     * @param resultData ApiResult里对应的data对象
     * @return
     */
    private List<DictConfigModel> getDictConfigs(Object resultData){
        List<DictConfigModel> configs = new LinkedList<>();

        if (resultData == null) {return configs;}

        Object obj = getInstanceObject(resultData);

        if(!ObjectUtils.isEmpty(obj)){configs = getDictConfigs(obj.getClass());}

        return configs;
    }

    /**
     * 找出标注有@Dict的属性配置集合
     * @param rootClass 实体对象class
     * @return 字典配置集合
     */
    private List<DictConfigModel> getDictConfigs(Class rootClass) {
        List<DictConfigModel> configs = new LinkedList<>();

        if (rootClass != null) {
            Field[] fields = rootClass.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if (field.isAnnotationPresent(Dict.class)) {
                    Dict dictConfig = field.getAnnotation(Dict.class);
                    configs.add(new DictConfigModel(field.getName(), dictConfig.dicCode(), dictConfig.dicText(), dictConfig.dictTable()));
                }
            }
            //获得父类的属性配置
            if (rootClass.getSuperclass() != Object.class) {
                configs.addAll(getDictConfigs(rootClass.getSuperclass()));
            }
        }

        return configs;
    }

    /**
     * 一次性把对象配置对应的单字典内容全部获取出,用于后续转换匹配
     * @param configs 标注有@Dict的属性配置集合
     * @return
     */
    List<DictModel> getAllSingleDictByConfigs(List<DictConfigModel> configs){
        List<String> dictCodes = new ArrayList<>();
        for (DictConfigModel config : configs) {
            //单字典
            if(StringUtils.isEmpty(config.getDictTable())){
                dictCodes.add(config.getDicCode());
            }
        }
        return queryManyDictByDictCodes(dictCodes);
    }

    /**
     * 通过字典编码集合列表一次性把单字典内容全部获取出字典内容(该抽象方法由用户去实现)
     * @param dictCodes 字典编码集合
     * @return
     */
    protected abstract List<DictModel> queryManyDictByDictCodes(List<String> dictCodes);

    /**
     * 通过查询指定table的 text code key 获取字典值
     * 查询字典表的数据 支持设置过滤条件、设置存储值作为in查询条件
     * @param dictTable 表名称 （或表名称 + " where k = 'v'"）
     * @param text 名称字段
     * @param code 码字段
     * @param values 码名映射中“码”的值集合 支持批量查询
     * @return
     */
    protected abstract List<DictModel>  queryTableDictByKeys(String dictTable,String text,String code,List<String> values);

}